
#include <WinSock2.h>  
#include <process.h>  
#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>
#include <vector>
#pragma comment(lib,"ws2_32.lib")  

//-------------协议号定义-----------
#define CMD_ONLINE_DATA 10  //在线信息
#define CMD_MSG         1   //发送消息

typedef struct _Client {
    SOCKET sClient;      ///客户端套接字   
    char userName[16];   ///客户端用户名  
    char IP[20];         ///客户端IP  
    char id;
}Client;

typedef struct Message {
    char from;    //发送者
    char to;    //接收者
    char data[1024];    //最大允许发送1024个字节
    int size;           //数据大小
}Msg;

int updateFlag = 0;             //信息更新标记
Client g_Client[100] = { 0 };  //所有客户端信息

int connectNum = 0;                             //当前连接数
SOCKADDR_IN ServerAddr = { 0 };                 ///服务端地址  
SOCKADDR_IN ClientAddr = { 0 };                 ///客户端地址  
int iClientAddrLen = sizeof(ClientAddr);
SOCKET g_ServerSocket = INVALID_SOCKET;         ///服务端套接字  
SOCKADDR_IN g_ClientAddr = { 0 };               ///客户端地址  
int g_iClientAddrLen = sizeof(g_ClientAddr);
USHORT uPort = 18000;                           ///服务器监听端口  
std::vector<Msg*> waitSendMsg;                   //等待发送的消息


//获得一个空的客户端对象
Client* getNullClient() {
    for (int i = 0; i < 100; i++) {
        if (g_Client[i].sClient == INVALID_SOCKET) {
            return &g_Client[i];
        }
    }
    return NULL;
}

//通过socket句柄获得Client对象
Client* getClientBySocket(SOCKET ClientSocket) {
    for (int i = 0; i < 100; i++) {
        if (g_Client[i].sClient == ClientSocket) {
            return &g_Client[i];
        }
    }
    return NULL;
}

//通过id获得Client对象
Client* getClientById(char id) {
    for (int i = 0; i < 100; i++) {
        if (g_Client[i].id == id) {
            return &g_Client[i];
        }
    }
    return NULL;
}
void ResetClient(Client* client) {
    if (client)
    {
        client->id = -1;
        client->sClient = INVALID_SOCKET;
        memset(client->IP, 0, sizeof(client->IP));
        memset(client->userName, 0, sizeof(client->userName));
    }
}
//
void onClientDisconnect(SOCKET ClientSocket) {
    Client* client = getClientBySocket(ClientSocket);
    if (client)
    {
        ResetClient(client);
        connectNum--;
        updateFlag = 1;
    }

}

void InitClients() {
    for (int i = 0; i < 100; i++) {
        ResetClient(&g_Client[i]);
    }
}

void CloseSocket(SOCKET socket) {
    onClientDisconnect(socket);
    closesocket(socket);
    WSACleanup();
}

void SendOnlineInfo()//发送在线信息
{
    if (updateFlag) {

        //组织数据
        int  index = 0;
        char onlineData[2048] = {};
        onlineData[index++] = CMD_ONLINE_DATA;
        for (int i = 0; i < 100; i++) {
            if (g_Client[i].id != -1 && g_Client[i].sClient != INVALID_SOCKET) {
                onlineData[index++] = g_Client[i].id;   //将id写入待发送
                int nameLen = strlen(g_Client[i].userName);
                memcpy(&onlineData[index++], &nameLen, 1); //将名字长度写入待发送
                memcpy(&onlineData[index], g_Client[i].userName, nameLen); //将名字写入待发送
                index += nameLen;
            }
        }

        //给每个在线玩家发送在线信息
        for (int i = 0; i < 100; i++) {
            if (g_Client[i].id != -1 && g_Client[i].sClient != INVALID_SOCKET) {
                send(g_Client[i].sClient, onlineData, index, 0);
            }
        }
        updateFlag = 0;     //发送后将标记复位
    }
}
//
void ParseMsg(SOCKET from, char* data, int datalen) {
    Message* msg = new Message();       //创建一个消息对象，类似于C语言的malloc
    Client* client = getClientBySocket(from);
    if (client)
    {
        msg->from = client->id;
        msg->to = data[0];
        memcpy(msg->data, data + 1, datalen - 1);
        msg->size = datalen - 1;
        waitSendMsg.push_back(msg);
    }
}

unsigned __stdcall THREAD_RECV(void* s) {
    SOCKET ClientSocket = *(SOCKET*)(s);
    Client* client = getClientBySocket(ClientSocket);
    if (client == NULL) return 0;
    char buffer[1024] = { 0 };
    while (1) {
        memset(buffer, 0, sizeof(buffer));
        int ret = recv(ClientSocket, buffer, sizeof(buffer), 0); ///接收数据
        if (ret == SOCKET_ERROR) {//接收错误
            printf("User disconnect ClientSocket=%d  error=%d\n", ClientSocket, errno);       //关闭socket连接
            onClientDisconnect(ClientSocket);
            closesocket(ClientSocket);
            return 0;
        }

        printf("Receive data from %s  data: %s\n", client->userName, buffer + 1);
        ParseMsg(ClientSocket, buffer, ret);
    }
}



unsigned __stdcall ThreadSend(void* param) {
    char buffer[1024] = "";
    while (1) {
        SendOnlineInfo(); //更新在线信息
        if (waitSendMsg.size() > 0) {
            for (int i = 0; i < waitSendMsg.size(); i++) {
                Msg* msg = waitSendMsg[i];
                Client* from = getClientById(msg->from);
                Client* target = getClientById(msg->to);
                if (from &&target)
                {
                    buffer[0] = CMD_MSG;
                    buffer[1] = msg->from;
                    memcpy(buffer + 2, msg->data, msg->size);
                    int len = send(target->sClient, buffer, msg->size + 2, 0);
                    if (SOCKET_ERROR == len) {
                        printf("send failed with error code: %d\n", WSAGetLastError());
                        onClientDisconnect(target->sClient);
                        closesocket(target->sClient);
                    }
                }
            }
            waitSendMsg.clear(); //发完消息清空待发送列表
        }
        else {
            Sleep(50);//休眠50ms
        }
    }

    return 0;
}

int main() {
    //初始化客户端信息
    InitClients();

    ///存放套接字信息的结构  
    WSADATA wsaData = { 0 };
    SOCKET ServerSocket = INVALID_SOCKET;///服务端套接字  
    SOCKET ClientSocket = INVALID_SOCKET;///客户端套接字

    if (WSAStartup(MAKEWORD(2, 2), &wsaData)) {
        printf("WSAStartup failed with error code: %d\n", WSAGetLastError());
        return -1;
    }
    ///判断版本  
    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
        printf("wVersion was not 2.2\n");
        return -1;
    }
    ///创建套接字  
    ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (ServerSocket == INVALID_SOCKET) {
        printf("socket failed with error code: %d\n", WSAGetLastError());
        return -1;
    }

    ///设置服务器地址  
    ServerAddr.sin_family = AF_INET;///连接方式  
    ServerAddr.sin_port = htons(uPort);///服务器监听端口  
    ServerAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);///任何客户端都能连接这个服务器  
    ///初始化套接字  
                                                        ///绑定服务器  
    if (SOCKET_ERROR == bind(ServerSocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr))) {
        printf("bind failed with error code: %d\n", WSAGetLastError());
        CloseSocket(ServerSocket);
        return -1;
    }
    ///监听有无客户端连接  
    if (SOCKET_ERROR == listen(ServerSocket, 1)) {
        printf("listen failed with error code: %d\n", WSAGetLastError());
        CloseSocket(ServerSocket);
        return -1;
    }
    printf("server launched\n");
    printf("wait user connect\n");
    _beginthreadex(NULL, 0, &ThreadSend, NULL, 0, NULL);        //启动转发消息的线程
    char name[16] = "";
    while (true)///让主线程休眠，不让它关闭TCP连接.  
    {
        if (connectNum <= 100) {
            SOCKET socket = accept(ServerSocket, (SOCKADDR*)&g_ClientAddr, &g_iClientAddrLen);
            if (socket == INVALID_SOCKET) {
                printf("accept failed with error code: %d\n", WSAGetLastError());
                CloseSocket(socket);
                continue;
            }
            Client* client = getNullClient();
            client->sClient = socket;

            //接受用户名
            int ret = recv(socket, name, sizeof(name), 0); ///接收数据  
            if (ret == SOCKET_ERROR) {
                printf("ClientSocket=%d  error=%d", socket, errno);
                CloseSocket(socket);
                continue;
            }
            client->id = connectNum+1;
            memcpy(client->userName, name, 16);
            printf("Successfuuly got a connection from IP:%s ,Port: %d,UerName: %s\n", inet_ntoa(g_ClientAddr.sin_addr), htons(g_ClientAddr.sin_port), client->userName);
            memcpy(client->IP, inet_ntoa(g_ClientAddr.sin_addr), sizeof(g_Client[connectNum].IP)); ///记录客户端IP
            send(client->sClient, &client->id, 1, 0);
            _beginthreadex(NULL, 0, &THREAD_RECV, &client->sClient, 0, 0);
            connectNum++;
            updateFlag = 1;
        }
        else {
            Sleep(1000);//连接已经达到最大,主线程休眠
        }
    }

    ///关闭套接字  
    int j = 1;
    while (j < 100) {
        if (g_Client[j].sClient != NULL)
            closesocket(g_Client[j].sClient);
        j++;
    }
    closesocket(g_ServerSocket);
    WSACleanup();
    return 0;
}